package com.bigdatastudio.auth.Filter;

import com.bigdatastudio.auth.utils.RoutePath;
import com.bigdatastudio.common.Utils.RedisUtil;
import com.bigdatastudio.common.Exception.CustomException;
import com.bigdatastudio.auth.utils.TokenUtil;
import com.bigdatastudio.auth.entity.UserDetailsModel;
import io.jsonwebtoken.Claims;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.Objects;


/**
 * @author xiao_jie
 * @date 2022/10/6 15:12
 * @describe 所要请求前必须要执行的方法
 */

@Component
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private TokenUtil tokenUtil1;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 直接给下面路径直接放行，不然执行到下面有权限设置，不需要认证的接口路径会报错
        for (String uri:
                RoutePath.getPath()) {
            if (Objects.equals(request.getRequestURI(),uri)){
                filterChain.doFilter(request, response);
                return;
            }
        }
        String token = request.getHeader("token");
        //token认证
        if (Objects.equals(token, "null") || Objects.isNull(token)) {
            filterChain.doFilter(request, response);   //  放行,没有进行用户身份信息认证
            return;
        }
        // 判断token的合法性  （判断签名是否合法）
        Claims claims = tokenUtil1.parseJWT(token);
        if (Objects.isNull(claims)) {      //token解析失败
            throw new CustomException(403, "token无效！！");
        }
        //合法toke
        String uuid = claims.getSubject();
        // 判断token是否过期和是否是最新生成的
        if (uuid != null && tokenUtil1.isTokenExpired(token) && tokenUtil1.isNewToken(uuid, token)) {
//        if (uuid!=null && tokenUtil1.isTokenExpired(token)){
            UserDetailsModel userDetailsModel = (UserDetailsModel) redisUtil.get(uuid);
            assert userDetailsModel != null;  //断言用户信息不为空
            Collection<? extends GrantedAuthority> authorities = userDetailsModel.getAuthorities();//用户权限
            //将认证结果封装到认证实例对象，保存到SpringSecurity容器
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetailsModel, uuid, authorities);
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        } else {
            redisUtil.del(uuid);
            tokenUtil1.deleteToken(uuid);
            throw new CustomException(403, "token已经过期！！");
        }
        filterChain.doFilter(request, response);
    }

}
